home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / merge.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  17KB  |  689 lines

  1. /*
  2.  * $Id: merge.c,v 0.91 1994/02/20 00:53:25 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *  Purpose:
  26.  *      Merge/concatinate/overlay two or more images to form a
  27.  *      single image.
  28.  *
  29.  */
  30.  
  31. #if !defined(lint) && defined(F_ID)
  32. char *id_mg = "$Id: merge.c,v 0.91 1994/02/20 00:53:25 zhao Pre-Release $";
  33. #endif
  34.  
  35. #include "bit.h"
  36. #include "extern.h"
  37.  
  38. /******************* Limits and defines **************************/
  39.  
  40. #define  MAXOFF  300.0        /* max overlapping   */
  41. #define  ImageOK (ir->w > 0)    /* if new image load */
  42.  
  43. /***************** Local variables ******************************/
  44.  
  45. static Rect_t imrect, *imr;    /* current image size (global)   */
  46. static Rect_t iirect, *ir;    /* loaded image size             */
  47. static IPTR mi;            /* the load image itself        */
  48. static IPTR oim;        /* input image                  */
  49. static int showmi = 0;        /* if show image while moving   */
  50. static int autosize;        /* if update image size         */
  51. static int alignreq = 4;    /* requested allignment         */
  52. static int sep;            /* sepetation                   */
  53. static int mergebot;        /* which on top if overlap      */
  54. static int fillc[4];        /* fill color                   */
  55. static FL_FORM *imerge;
  56. static int offx, offy;        /* where original image is      */
  57.  
  58. /******* Possible operations on the image ******************/
  59. typedef struct
  60.   {
  61.       const char *name;        /* operation name              */
  62.       int matop;        /* known by the matrix rouines */
  63.   }
  64. Matop;
  65.  
  66. static Matop matops[] =
  67. {
  68.     {"Overwrite", O_NONE,},
  69.     {" Add ", O_ADD},
  70.     {" Sub ", O_SUB},
  71.     {" Diff ", O_DIFF},
  72.     {" XOR ", O_XOR},
  73.     {" Mask ", O_MASK}
  74. };
  75.  
  76. static Matop *mop = matops;
  77.  
  78. /******* Local functions **************************************/
  79.  
  80. static void create_form_imerge(void);
  81. static int merge_init(IPTR, int);
  82.  
  83. static void
  84. show_image(int ox, int oy, int x, int y)
  85. {
  86.     if (!mi || !showmi)
  87.     return;
  88.  
  89.     mv_ras_obj(mi->mraster, mi->w, mi->h, ox, oy, x, y);
  90. }
  91.  
  92.  
  93. /******************************************************************
  94.  * Global entry point
  95.  *****************************************************************/
  96.  
  97. int
  98. do_merge(IPTR im)
  99. {
  100.     short val;
  101.     long dev;
  102.  
  103.     create_form_imerge();
  104.     deactivate_all_forms();
  105.     oim = im;
  106.     mi = 0;
  107.  
  108.     /*
  109.      * initialize and install handler to handle window manager's resize and
  110.      * reposition events
  111.      */
  112.  
  113.     merge_init(im, 0);
  114.     install_wm_handler(merge_init);
  115.  
  116.     /* disable bounds checking */
  117.  
  118.     set_rubber_bounds(0, 0, 0, 0, 0);
  119.  
  120.     bit_show_form(imerge, FL_PLACE_MOUSE, 0, "Imerge");
  121.  
  122.     /* looping until ESC or done button is pressed */
  123.     do
  124.       {
  125.       if (alignreq == 0 && ImageOK)
  126.         {
  127.         dev = rubber_info(win_id, &val,
  128.                   &ir->x, &ir->y, &ir->w, &ir->h, 2, 0);
  129.         dev = bit_handle_event(dev, val);
  130.         }
  131.       else
  132.           dev = bit_qread(&val);
  133.       }
  134.     while (!(dev == KEYBD && val == 27));
  135.  
  136.     /* clean up */
  137.     remove_wm_handler(merge_init);
  138.     rubber_finish();
  139.     bit_hide_form(imerge);
  140.     free_image(mi);
  141.     fl_activate_all_forms();
  142.     return 0;
  143. }
  144.  
  145.  
  146. /*************************************************************
  147.  * find where the rubber should be (ix, iy). The current image
  148.  * location is given by (xi, xf, w, h)
  149.  *
  150.  * Location request is defined as follows:
  151.  *
  152.  *    7 8 9
  153.  * 17       19
  154.  *  4 image 6
  155.  * 11       13
  156.  *    1 2 3
  157.  *
  158.  *************************************************************/
  159.  
  160. /* ARGSUSED */
  161. static void
  162. get_location(IPTR im)
  163. {
  164.     int xf = imr->x + imr->w - 1;
  165.     int yf = imr->y + imr->h - 1;
  166.     int xi = imr->x, yi = imr->y;
  167.     int w = imr->w, h = imr->h;
  168.     int iw = ir->w, ih = imr->h;
  169.  
  170.     switch (alignreq)
  171.       {
  172.       case 1:
  173.       ir->x = xi;
  174.       ir->y = yi - ih - sep;
  175.       break;
  176.       case 2:
  177.       ir->x = xi + (w - iw) / 2;
  178.       ir->y = yi - ih - sep;
  179.       break;
  180.       case 3:
  181.       ir->x = xf - iw + 1;
  182.       ir->y = yi - ih - sep;
  183.       break;
  184.       case 7:
  185.       ir->x = xi;
  186.       ir->y = yf + 1 + sep;
  187.       break;
  188.       case 8:
  189.       ir->x = xi + (w - iw) / 2;
  190.       ir->y = yf + 1 + sep;
  191.       break;
  192.       case 9:
  193.       ir->x = xf - iw + 1;
  194.       ir->y = yf + 1 + sep;
  195.       break;
  196.       case 6:
  197.       ir->x = xf + 1 + sep;
  198.       ir->y = yi + (h - ih) / 2;
  199.       break;
  200.       case 11:
  201.       ir->x = xi - iw - sep;
  202.       ir->y = yi;
  203.       break;
  204.       case 17:
  205.       ir->x = xi - iw - sep;
  206.       ir->y = yf - ih + 1;
  207.       break;
  208.       case 4:
  209.       ir->x = xi - iw - sep;
  210.       ir->y = yi + (h - ih) / 2;
  211.       break;
  212.       case 19:
  213.       ir->x = xf + 1 + sep;
  214.       ir->y = yf - ih + 1;
  215.       break;
  216.       case 13:
  217.       ir->x = xf + 1 + sep;
  218.       ir->y = yi;
  219.       break;
  220.       }
  221. }
  222.  
  223. static void
  224. place_rubber(IPTR im)
  225. {
  226.     int ox = ir->x, oy = ir->y;
  227.  
  228.     if (ir->w == 0 || ir->h == 0)
  229.     return;
  230.  
  231.     get_location(im);
  232.     set_current_window(win_id);
  233.  
  234.     rubber_moveto(&ir->x, &ir->y, &ir->w, &ir->h);
  235.     show_image(ox, oy, ir->x, ir->y);
  236.  
  237.     rubber_show(alignreq ? 1 : 2);    /* change rubber_color */
  238.  
  239. }
  240.  
  241. /******************************************************************
  242.  * Initialize the rubber band location. If wme == 1, it is called
  243.  * by the window manager envents handler or purposely not updating
  244.  * current alignment reference
  245.  ******************************************************************/
  246.  
  247. static int
  248. merge_init(IPTR im, int wme)
  249. {
  250.  
  251.     if (!wme)
  252.       {
  253.       offx = offy = 0;
  254.       imr = &imrect;
  255.       copy_rect(imr, img_rect(im));
  256.       ir = &iirect;
  257.       ir->w = ir->h = 0;
  258.       }
  259.     else
  260.       {
  261.       /* image & window size might've been changed */
  262.       imr->x = im->xi + offx;
  263.       imr->y = im->yi + offy;
  264.       }
  265.     place_rubber(im);
  266.     return 0;
  267. }
  268.  
  269.  
  270. /********** Load the image to merge *******************************/
  271.  
  272. /*ARGSUSED*/
  273. static void
  274. load_cb(FL_OBJECT * ob, long q)
  275. {
  276.     const char *fn = getfilename("Files to merge", ".", "*", "", 0);
  277.     IPTR tmpi;
  278.  
  279.  
  280.     if (!fn || !(tmpi = load_image(fn)))
  281.     return;
  282.  
  283.     free_image(mi);
  284.  
  285.     /* show current image info, which was reset in load_image */
  286.     update_image_info(imgptr);
  287.  
  288.     mi = tmpi;
  289.     set_current_window(win_id);
  290.     rubber_hide();
  291.  
  292.     ir->w = tmpi->w;
  293.     ir->h = tmpi->h;
  294.     get_location(imgptr);
  295.     rubber_new(win_id, ir->x, ir->y, ir->w, ir->h, alignreq ? 1 : 2);
  296. }
  297.  
  298. /*ARGSUSED*/
  299. static void
  300. top_bottom_cb(FL_OBJECT * ob, long q)
  301. {
  302.     mergebot = fl_get_choice(ob) - 1;
  303. }
  304.  
  305. /*ARGSUSED*/
  306. static void
  307. update_size_cb(FL_OBJECT * ob, long q)
  308. {
  309.     merge_init(imgptr, 0);
  310. }
  311.  
  312. /******************************************************************
  313.  * Do the actual merging, taking into account the top/bottom
  314.  * settings
  315.  ******************************************************************/
  316.  
  317. /*ARGSUSED*/
  318. static void
  319. merge_it(FL_OBJECT * ob, long q)
  320. {
  321.     rgba_t **mat, fcolor;
  322.     const Rect_t *sum, *uu;
  323.  
  324.     if (!ImageOK)
  325.     return;
  326.  
  327.     /* figure out the new image size */
  328.  
  329.     sum = sum_rect(img_rect(oim), ir);
  330.  
  331.  
  332.     /* merged image will always be in RGB */
  333.     if (img_convert_type(oim, T_RGBA) || img_convert_type(mi, T_RGBA))
  334.     return;
  335.  
  336.     show_busy("PleaseWait ...");
  337.  
  338.     /* get the new image matrix and initialize to the request bk color */
  339.  
  340.     mat = get_mat(sum->h, sum->w, sizeof(rgba_t));
  341.     fcolor = Pack(fillc[0], fillc[1], fillc[2]);
  342.     init_mat(mat, sum->h, sum->w, sizeof(rgba_t), fcolor);
  343.  
  344.     mi->xi = ir->x;
  345.     mi->yi = ir->y;
  346.     mi->xf = ir->x + ir->w - 1;
  347.     mi->yf = ir->y + ir->h - 1;
  348.  
  349.     /*
  350.      * always remember where the original image is by remembering the
  351.      * distance from lower-left corner of the original image to the
  352.      * lower-left corner of the merged image
  353.      */
  354.  
  355.     offx = imr->x - sum->x;
  356.     offy = imr->y - sum->y;
  357.  
  358.  
  359.     /*
  360.      * further optimization is possible in that for concatenation, the image
  361.      * itself IS the submat and we can simple use the image matrix and thus
  362.      * avoiding the submat operation
  363.      */
  364.  
  365.     if (mergebot)        /* new image at bottom */
  366.       {
  367.       put_submat(mat, sum->h, sum->w, mi->mraster,
  368.              ir->y - sum->y, ir->x - sum->x,
  369.              ir->h, ir->w, sizeof(rgba_t));
  370.       put_submat(mat, sum->h, sum->w, oim->mraster,
  371.              oim->yi - sum->y, oim->xi - sum->x,
  372.              oim->h, oim->w, sizeof(rgba_t));
  373.       }
  374.     else
  375.       {
  376.       /* insert subimages */
  377.       put_submat(mat, sum->h, sum->w, oim->mraster,
  378.              oim->yi - sum->y, oim->xi - sum->x,
  379.              oim->h, oim->w, sizeof(rgba_t));
  380.       put_submat(mat, sum->h, sum->w, mi->mraster,
  381.              ir->y - sum->y, ir->x - sum->x,
  382.              ir->h, ir->w, sizeof(rgba_t));
  383.       }
  384.  
  385.     /*
  386.      * do requested operation on the overlapping part of the images only,
  387.      * taking into consideration  the top/bottom requests
  388.      */
  389.  
  390.     if (mop->matop != O_NONE && (uu = union_rect(img_rect(oim), ir)))
  391.       {
  392.       rgba_t **m1, **m2;
  393.       Rect_t urect;
  394.       Rect_t *u = &urect;
  395.  
  396.       copy_rect(u, uu);
  397.  
  398.       /*
  399.        * m1 is the input matrix,  m2 is the image old image and mat is
  400.        * the resulting image
  401.        */
  402.  
  403.       m1 = get_subimage(mi, u->x, u->y, u->w, u->h);
  404.       m2 = get_subimage(oim, u->x, u->y, u->w, u->h);
  405.  
  406.       set_mat_op(mop->matop);
  407.       M_info("Merge", "Op=%s\n", mop->name);
  408.  
  409.       put_submat(mergebot ? m1 : m2, u->h, u->w, mergebot ? m2 : m1,
  410.              0, 0, u->h - 1, u->w - 1, sizeof(**m2));
  411.  
  412.       set_mat_op(O_NONE);
  413.  
  414.       put_submat(mat, sum->h, sum->w, mergebot ? m1 : m2,
  415.              u->y - sum->y, u->x - sum->x,
  416.              u->h, u->w, sizeof(rgba_t));
  417.       free_mat(m1);
  418.       free_mat(m2);
  419.       }
  420.  
  421.     fill_image_struct(oim, mat, sum->h, sum->w, T_RGBA);
  422.  
  423.     set_current_window(win_id);
  424.     set_display_mode(oim);
  425.  
  426.     /* don't move the image unless requested */
  427.     if (!autosize)
  428.       {
  429.       oim->xi = sum->x;
  430.       oim->yi = sum->y;
  431.       oim->xf = oim->xi + sum->w - 1;
  432.       oim->yf = oim->yi + sum->h - 1;
  433.       Rectwrite(sum->x, sum->y,
  434.             sum->x + sum->w - 1, sum->y + sum->h - 1, oim->raster);
  435.       }
  436.     else
  437.       {
  438.       oim->io->display(oim, 0, double_buf);
  439.       }
  440.  
  441.     merge_init(oim, !autosize);    /* re-initialize */
  442.     end_busy();
  443. }
  444.  
  445. /***************** Alignment information **************
  446.  *
  447.  *    7 8 9
  448.  * 17      19
  449.  * 4        6
  450.  * 11      13
  451.  *   1 2 3
  452.  *******************************************************/
  453.  
  454. #if 0
  455. extern void set_rubber_info_cb(void (*)(int, int, int, int));
  456. #endif
  457.  
  458. /* ARGSUSED */
  459. static void
  460. alignment_cb(FL_OBJECT * ob, long q)
  461. {
  462.     if (alignreq == 0)        /* manual */
  463.       {
  464.       set_rubber_info_cb(0);
  465.       end_rubber_info();
  466.       }
  467.  
  468.     alignreq = q;
  469.     place_rubber(imgptr);
  470. #if 0
  471.     if (alignreq == 0)
  472.       {
  473.       set_rubber_info_cb(show_image);
  474.       }
  475. #endif
  476. }
  477.  
  478. /************ Terminating Merge function *************/
  479. /* ARGSUSED*/
  480. static void
  481. merge_done(FL_OBJECT * ob, long q)
  482. {
  483.     fl_qenter(KEYBD, 27);
  484. }
  485.  
  486. /************* Seperation from the image ***************/
  487. /*ARGSUSED*/
  488. static void
  489. sep_cb(FL_OBJECT * ob, long q)
  490. {
  491.     sep = fl_get_counter_value(ob);
  492.     place_rubber(imgptr);
  493. }
  494.  
  495. #define FILLCI 300
  496.  
  497. /***************** Fill color ***********************/
  498.  
  499. /* ARGSUSED*/
  500. static void
  501. fc_cb(FL_OBJECT * ob, long q)
  502. {
  503.     get_color(imgptr, fillc, 1);/* block */
  504.     fl_mapcolor(FILLCI, fillc[0], fillc[1], fillc[2]);
  505.     fl_redraw_object(ob);
  506. }
  507.  
  508. /******** Get the requested operation struct *****/
  509. static void
  510. operation_cb(FL_OBJECT * ob, long q)
  511. {
  512.     if ((q = fl_get_choice(ob)) > 0)
  513.     mop = matops + q - 1;
  514. }
  515.  
  516. static FL_OBJECT *ialign;
  517.  
  518. static void
  519. create_form_imerge(void)
  520. {
  521.     FL_OBJECT *obj;
  522.     float dx, dy, x, y;
  523.     Matop *m = matops, *ms = m + sizeof(matops) / sizeof(matops[0]);
  524.  
  525.     if (imerge)
  526.     return;
  527.  
  528.     imerge = fl_bgn_form(FL_NO_BOX, 275.0, 250.0);
  529.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 275.0, 250.0, "");
  530.     obj = fl_add_text(FL_NT, 35.0, 210.0, 200.0, 30.0, "Image Merge");
  531.     fl_set_object_lcol(obj, 4);
  532.     fl_set_object_lsize(obj, 16.0);
  533.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  534.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  535.  
  536.     obj = fl_add_button(FL_HB, 0, 0.0, 275.0, 250.0, "");
  537.     fl_set_call_back(obj, help_cb, HELP_MERGE);
  538.  
  539.     dx = 75.0;
  540.     dy = 25.0;
  541.     x = 185.0;
  542.     y = 175.0;
  543.  
  544.     /* Operations  */
  545.     obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
  546.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  547.     fl_set_choice_fontsize(obj, 10.0);
  548.  
  549.     while (m < ms)
  550.       {
  551.       fl_addto_choice(obj, m->name);
  552.       m++;
  553.       }
  554.  
  555.     fl_set_choice(obj, 1);
  556.     fl_set_call_back(obj, operation_cb, 0);
  557.     y -= dy + 1;
  558.  
  559.     /* top/bottom */
  560.     obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
  561.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  562.     fl_set_choice_fontsize(obj, 10.0);
  563.     fl_addto_choice(obj, "Top");
  564.     fl_addto_choice(obj, "Bottom");
  565.     fl_set_choice(obj, mergebot + 1);
  566.     fl_set_call_back(obj, top_bottom_cb, 0);
  567.     y -= dy + 5;
  568.  
  569.     dx = 75.0;
  570.     dy = 25.0;
  571.     x = 185.0;
  572.  
  573.     obj = fl_add_button(FL_NB, x, y, dx, dy, "FillColor");
  574.     fl_set_object_lsize(obj, 10.0);
  575.     fl_set_object_color(obj, FILLCI, FL_GREEN);
  576.     fl_set_object_lcol(obj, FL_MAGENTA);
  577.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  578.     fl_set_call_back(obj, fc_cb, 0);
  579.     y -= dy;
  580.  
  581.     obj = fl_add_button(FL_NB, x, y, dx, dy, "UpdateSize");
  582.     fl_set_object_lsize(obj, 10.0);
  583.     fl_set_call_back(obj, update_size_cb, 0);
  584.     y -= dy;
  585.  
  586.     obj = fl_add_button(FL_NB, x, y, dx, dy, "Image2M");
  587.     fl_set_object_lsize(obj, 10.0);
  588.     fl_set_call_back(obj, load_cb, 0);
  589.     y -= dy + 5;
  590.  
  591.     obj = fl_add_button(FL_NB, x, y, dx, dy, "Merge");
  592.     fl_set_object_lsize(obj, 10.0);
  593.     fl_set_call_back(obj, merge_it, 0);
  594.     y -= dy;
  595.  
  596.     obj = fl_add_button(FL_NB, x, y, dx, dy, "Done");
  597.     fl_set_object_lsize(obj, 10.0);
  598.     fl_set_call_back(obj, merge_done, 0);
  599.  
  600.     /* Seperation control */
  601.     obj = fl_add_counter(FL_NC, 30.0, 15.0, 130.0, 25.0, "");
  602.     fl_set_counter_precision(obj, 0);
  603.     fl_set_counter_bounds(obj, -MAXOFF, MAXOFF);
  604.     fl_set_counter_step(obj, 1.0, 10.0);
  605.     fl_set_counter_value(obj, sep);
  606.     fl_set_call_back(obj, sep_cb, 0);
  607.  
  608.     /* all the alignment buttons */
  609. /*   7 8 9
  610.   17       19
  611.   4         6
  612.   11       13
  613.      1 2 3
  614. */
  615.     ialign = fl_bgn_group();
  616.  
  617.     dx = dy = 30.0;
  618.     y = 10;
  619.  
  620.     obj = fl_add_button(FL_RB, 55.0, y + 70.0, 90.0, 90.0, "Manual");
  621.     fl_set_object_color(obj, 47, 12);
  622.     fl_set_call_back(obj, alignment_cb, 0);
  623.  
  624.     /* center buttons */
  625.     /* right-center */
  626.     obj = fl_add_button(FL_RB, 145.0, y + 100.0, dx, dy, "@circle");
  627.     fl_set_object_lcol(obj, 1);
  628.     fl_set_call_back(obj, alignment_cb, 6);
  629.     fl_set_button(obj, alignreq == 6);
  630.     /* bottom */
  631.     obj = fl_add_button(FL_RB, 85.0, y + 40.0, dx, dy, "@circle");
  632.     fl_set_object_lcol(obj, 1);
  633.     fl_set_call_back(obj, alignment_cb, 2);
  634.     fl_set_button(obj, alignreq == 2);
  635.     /* left */
  636.     obj = fl_add_button(FL_RB, 25.0, y + 100.0, dx, dy, "@circle");
  637.     fl_set_object_lcol(obj, 1);
  638.     fl_set_call_back(obj, alignment_cb, 4);
  639.     fl_set_button(obj, alignreq == 4);
  640.     /* top */
  641.     obj = fl_add_button(FL_RB, 85.0, y + 160.0, dx, dy, "@circle");
  642.     fl_set_object_lcol(obj, 1);
  643.     fl_set_call_back(obj, alignment_cb, 8);
  644.     fl_set_button(obj, alignreq == 8);
  645.  
  646.     /* bottom two */
  647.     obj = fl_add_button(FL_RB, 55.0, y + 40.0, dx, dy, "@4");
  648.     fl_set_object_lcol(obj, 1);
  649.     fl_set_call_back(obj, alignment_cb, 1);
  650.     fl_set_button(obj, alignreq == 1);
  651.  
  652.     obj = fl_add_button(FL_RB, 115.0, y + 40.0, dx, dy, "@6");
  653.     fl_set_object_lcol(obj, 1);
  654.     fl_set_call_back(obj, alignment_cb, 3);
  655.     fl_set_button(obj, alignreq == 3);
  656.  
  657.     /* top two */
  658.     obj = fl_add_button(FL_RB, 55.0, y + 160.0, dx, dy, "@4");
  659.     fl_set_object_lcol(obj, 1);
  660.     fl_set_call_back(obj, alignment_cb, 7);
  661.     fl_set_button(obj, alignreq == 7);
  662.     obj = fl_add_button(FL_RB, 115.0, y + 160.0, dx, dy, "@6");
  663.     fl_set_object_lcol(obj, 1);
  664.     fl_set_call_back(obj, alignment_cb, 9);
  665.     fl_set_button(obj, alignreq == 9);
  666.  
  667.     /* left two */
  668.     obj = fl_add_button(FL_RB, 25.0, y + 70.0, dx, dy, "@2");
  669.     fl_set_object_lcol(obj, 1);
  670.     fl_set_call_back(obj, alignment_cb, 11);
  671.     fl_set_button(obj, alignreq == 11);
  672.     obj = fl_add_button(FL_RB, 25.0, y + 130.0, dx, dy, "@8");
  673.     fl_set_object_lcol(obj, 1);
  674.     fl_set_call_back(obj, alignment_cb, 17);
  675.     fl_set_button(obj, alignreq == 17);
  676.  
  677.     /* right two */
  678.     obj = fl_add_button(FL_RB, 145.0, y + 130.0, dx, dy, "@8");
  679.     fl_set_object_lcol(obj, 1);
  680.     fl_set_call_back(obj, alignment_cb, 19);
  681.     fl_set_button(obj, alignreq == 19);
  682.     obj = fl_add_button(FL_RB, 145.0, y + 70.0, dx, dy, "@2");
  683.     fl_set_object_lcol(obj, 1);
  684.     fl_set_call_back(obj, alignment_cb, 13);
  685.     fl_set_button(obj, alignreq == 13);
  686.     fl_end_group();
  687.     fl_end_form();
  688. }
  689.